/**
 * Copyright (c) 2023 murenchao
 * taomu is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *       http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package cool.taomu.ssh

import com.jcraft.jsch.ChannelExec
import com.jcraft.jsch.ChannelSftp
import com.jcraft.jsch.ChannelShell
import com.jcraft.jsch.JSch
import com.jcraft.jsch.Session
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.PipedInputStream
import java.io.PipedOutputStream
import java.io.PrintWriter
import java.util.Properties
import org.apache.commons.io.IOUtils
import org.slf4j.LoggerFactory

class JschUtils implements AutoCloseable {

	val static LOG = LoggerFactory.getLogger(JschUtils);

	Session session = null;

	new(String host, String uname, String upass, int port) {
		try {
			var jsch = new JSch();
			this.session = jsch.getSession(uname, host, port);
			this.session.password = upass;
			// id_rsa jsch.addIdentity("","");
			var config = new Properties();
			config.put("StrictHostKeyChecking", "no");
			this.session.config = config;
			this.session.timeout = 60000000;
			this.session.connect
			if (this.session.isConnected) {
				LOG.info("链接成功")
			} else {
				LOG.info("链接失败")
			}
		} catch (Exception ex) {
			LOG.info("失败", ex)
		}
	}

	override close() throws Exception {
		if (this.session !== null) {
			this.session.disconnect;
		}
	}

	static class Ssh implements AutoCloseable {
		ChannelExec exec = null;

		new(Session session) {
			var channel = session.openChannel("exec");
			this.exec = channel as ChannelExec;
		}

		def exec(String cmd, String charset) {
			exec.command = cmd;
			exec.connect;
			var input = exec.inputStream;
			return IOUtils.toString(input, charset);
		}

		override close() throws Exception {
			if (exec !== null) {
				this.exec.disconnect
			}
		}
	}

	def Ssh() {
		return new Ssh(this.session);
	}

	static class Sftp implements AutoCloseable {
		var ChannelSftp sftp = null;

		new(Session session) {
			var channel = session.openChannel("sftp");
			sftp = channel as ChannelSftp;
			sftp.connect;
		}

		override close() throws Exception {
			if (sftp !== null) {
				this.sftp.disconnect
			}
		}

		def get(String file) {
			var bos = new ByteArrayOutputStream();
			this.sftp.get(file, bos, new SftpProgresssMonitorImpl);
			return bos.toByteArray;
		}

		def get(String src, String dst) {
			this.sftp.get(src, dst, new SftpProgresssMonitorImpl);
		}

		def void put(String file, byte[] content) {
			var bis = new ByteArrayInputStream(content);
			this.sftp.put(bis, file, new SftpProgresssMonitorImpl);
		}

		def void put(String src, String dst) {
			this.sftp.put(src, dst, new SftpProgresssMonitorImpl);
		}

		def void cd(String directory) {
			this.sftp.cd(directory);
		}
	}

	def Sftp() {
		return new Sftp(this.session);
	}

	static class Shell implements AutoCloseable {
		var ChannelShell channel = null;

		new(Session session) {
			this.channel = session.openChannel("shell") as ChannelShell;

		}

		def exec(String[] content) {
			try(var pis = new PipedInputStream) {
				try(var pos = new PipedOutputStream) {
					try(var pw = new PrintWriter(pos)) {
						channel.inputStream = new PipedInputStream(pos);
						channel.outputStream = new PipedOutputStream(pis);
						channel.connect;
						for(it : content){
							pw.println(it);
						}
						pw.flush();
						return IOUtils.toString(pis, "UTF-8");
					}
				}
			}
		}

		override close() throws Exception {
			if (channel !== null) {
				channel.disconnect
			}
		}
	}

	def Shell() {
		return new Shell(this.session);
	}
}
